#include "item-sort-model.h"

#include <QAbstractItemModel>
#include <QDebug>

ItemSortModel::ItemSortModel(QObject *parent) : QSortFilterProxyModel(parent)
{

}

void ItemSortModel::setSourceModel(QAbstractItemModel *sourceModel)
{
    QSortFilterProxyModel::setSourceModel(sourceModel);
    connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &ItemSortModel::onRowInsert);
    connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ItemSortModel::onRowRemoved);
    connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &ItemSortModel::invalidate);
    connect(sourceModel, &QAbstractItemModel::dataChanged, this, &ItemSortModel::dataChanged);
    initOrderData();
    m_sourceModel = qobject_cast<StatusNotifierModel*>(sourceModel);
}

QModelIndex ItemSortModel::index(int row, int column, const QModelIndex &parent) const
{
    if (row < 0 || column != 0) {
        return {};
    }
    return createIndex(row, column);
}

QVariant ItemSortModel::data(const QModelIndex &index, int role) const
{
    return sourceModel()->data(mapToSource(index), role);
}

QModelIndex ItemSortModel::mapToSource(const QModelIndex &proxyIndex) const
{
    return m_order.key(proxyIndex.row());
}

QModelIndex ItemSortModel::mapFromSource(const QModelIndex &sourceIndex) const
{
    return index(m_order.value(sourceIndex), 0, {});
}

int ItemSortModel::rowCount(const QModelIndex &parent) const
{
    return sourceModel()->rowCount();
}

void ItemSortModel::setOrder(const QModelIndex &index, int order)
{
    QModelIndex sourceIndex = mapToSource(index);
    int oldOrder = m_order.value(sourceIndex);
    if(oldOrder == order) {
        return;
    }
    QHashIterator<QPersistentModelIndex, int> iter(m_order);
    if(oldOrder < order) {
        iter.toFront();
        beginResetModel();
        m_order.insert(sourceIndex, order);
        while(iter.hasNext()) {
            iter.next();
            if(iter.value() > oldOrder && iter.value() <= order && iter.key() != sourceIndex) {
                m_order.insert(iter.key(), iter.value() - 1);
            }
        }
        endResetModel();
    } else {
        iter.toFront();
        beginResetModel();
        m_order.insert(sourceIndex, order);
        while(iter.hasNext()) {
            iter.next();
            if(iter.value() >= order && iter.value() < oldOrder && iter.key() != sourceIndex) {
                m_order.insert(iter.key(), iter.value() + 1);
            }
        }
        endResetModel();
    }
    invalidate();
}

void ItemSortModel::activate(const int &index)
{
    QModelIndex i = this->index(index, 0, QModelIndex());
    m_sourceModel->onActivate(mapToSource(i).row());
}

void ItemSortModel::contextMenu(const int &index)
{
    QModelIndex i = this->index(index, 0, QModelIndex());
    m_sourceModel->onContextMenu(mapToSource(i).row());
}

bool ItemSortModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
    return m_order.value(mapToSource(source_left)) < m_order.value(mapToSource(source_right));
}

void ItemSortModel::onRowRemoved(const QModelIndex &parent, int first, int last)
{
    for(int sourceIndex = first; sourceIndex <= last; ++sourceIndex) {
        QModelIndex removeIndex = sourceModel()->index(sourceIndex, 0);
        int order = m_order.value(removeIndex);
        beginRemoveRows(QModelIndex(), order, order);
        m_order.remove(removeIndex);
        QHashIterator<QPersistentModelIndex, int> iter(m_order);
        while(iter.hasNext()) {
            iter.next();
            if(iter.value() > order) {
                m_order.insert(iter.key(), iter.value() - 1);
            }
        }
        endRemoveRows();
    }
}

void ItemSortModel::onRowInsert(const QModelIndex &parent, int first, int last)
{
    beginResetModel();
    for(int sourceIndex = first; sourceIndex <= last; ++sourceIndex) {
        QModelIndex insertIndex = sourceModel()->index(sourceIndex, 0);
        m_order.insert(insertIndex, m_order.size());
    }
    endResetModel();
    invalidate();
}

void ItemSortModel::initOrderData()
{
    beginResetModel();
    for(int i = 0; i < sourceModel()->rowCount(); ++i) {
        QModelIndex sourceIndex = sourceModel()->index(i, 0);
        m_order.insert(sourceIndex, m_order.size());
    }
    endResetModel();
    invalidate();
}

